package cn.ciis.basic.websocket;

import cn.ciis.basic.model.Account;
import cn.ciis.sys.account.AccountAdminService;
import cn.ciis.sys.login.LoginService;
import cn.hutool.core.util.StrUtil;
import com.baomidou.kisso.security.token.SSOToken;
import com.jfinal.aop.Aop;
import com.jfinal.core.Controller;
import com.jfinal.kit.Kv;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;

/**
 * @author 冉志林
 * @description
 * @date 3/14/2019
 */
@ServerEndpoint(value = "/socket.ws", configurator = GetCookieConfigurator.class)
public class AuthorityWebSocket extends Controller {

    private AccountAdminService accountService = new AccountAdminService();
    LoginService loginService = Aop.get(LoginService.class);

    public static final Map<String, Session> USER_SOCKET_SESSION_MAP;

    static {
        USER_SOCKET_SESSION_MAP = new HashMap<>();
    }

    /**
     * @return void @Author 冉志林
     * @Description 给单个用户发送消息 @Date 3/14/2019 @Param [userId, message]
     */
    public void sendMsg(String userId, String message) {
        Session session1 = USER_SOCKET_SESSION_MAP.get(userId);

        if(session1 !=null && session1.isOpen()){
            message(message, session1);
        }
    }

    /**
     * @return void @Author 冉志林 @Description // 接收消息和回复消息 @Date 3/14/2019 @Param [message,
     * session]
     */
    @OnMessage
    public void message(String message, Session session) {
        session.getAsyncRemote().sendText(message);
    }

    @SuppressWarnings("unchecked")
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        String sessionId = (String) config.getUserProperties().get(String.class.getName());

        if(StrUtil.isNotBlank(sessionId)) {
            SSOToken ssoToken = null;

            try {
                ssoToken = SSOToken.parser(sessionId);
            }catch (Exception e){
                LogKit.error("错误的登录令牌");
            }

            if(ssoToken != null){
                Account user = loginService.getLoginAccountWithSessionId(ssoToken.getIssuer());
                if(user != null) {
                    String key =user.getWebSocketSessionKey();

                    Session old = USER_SOCKET_SESSION_MAP.get(key);

                    if(old != null){

                        if(!old.getId().equals(session.getId())){
                            old.getAsyncRemote().sendText(Kv.by("msg", "您的账号在其它地方登录，您已被强制下线！").toJson());
                            try {
                                old.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            USER_SOCKET_SESSION_MAP.put(key, session);
                            LogKit.info("WebSocket:用户[" + user.getUserName()+ "]已经建立连接");
                        }
                    }else{
                        USER_SOCKET_SESSION_MAP.put(key, session);
                        LogKit.info("WebSocket:用户[" + user.getUserName()+ "]已经建立连接");
                    }

                }else{
                    session.getAsyncRemote().sendText("登录信息已失效");
                    try {
                        session.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }else {
                try {
                    session.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }else{
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            LogKit.error("WebSocket:用户未登录，无法建立连接");
        }

    }

    @OnClose
    public void onClose(Session session) throws Exception {
        LogKit.error("WebSocket: " + session.getId() + "已经关闭");

        Set<String> keySet = USER_SOCKET_SESSION_MAP.keySet();

        for (String key : keySet) {

            if(USER_SOCKET_SESSION_MAP.get(key) !=null){

                if(USER_SOCKET_SESSION_MAP.get(key).getId().equals(session.getId())){
                    USER_SOCKET_SESSION_MAP.remove(key);
                    break;
                }

            }
        }
    }

    @OnError
    public void onError(Session session, Throwable error) throws Exception {
        error.printStackTrace();
        onClose(session);
        Iterator<Entry<String, Session>> it = USER_SOCKET_SESSION_MAP.entrySet().iterator();
        // 移除Socket会话
        while (it.hasNext()) {
            Entry<String, Session> entry = it.next();
            if (entry.getValue().getId().equals(session.getId())) {
                USER_SOCKET_SESSION_MAP.remove(entry.getKey());
                break;
            }
        }
    }

    /**
     * 给所有用户发送信息
     * @param msg
     */
    public static void sendAll(String msg){
        if(StrKit.isBlank(msg)){
            msg = "服务器维护！关闭连接";
        }

        Ret ret = Ret.by("code", 500).set("msg", msg);

        Set<String> strings = USER_SOCKET_SESSION_MAP.keySet();
        for (String key : strings) {
            USER_SOCKET_SESSION_MAP.get(key).getAsyncRemote().sendText(ret.toJson());
        }
    }
    /**
     * 关闭所有客户端通信
     */
    public static void closeAll(String msg) {

        if(StrKit.isBlank(msg)){
            msg = "服务器维护！关闭连接";
        }

        Ret ret = Ret.by("code", 500).set("msg", msg);

        Set<String> strings = USER_SOCKET_SESSION_MAP.keySet();
        for (String key : strings) {
            USER_SOCKET_SESSION_MAP.get(key).getAsyncRemote().sendText(ret.toJson());
            try {
                USER_SOCKET_SESSION_MAP.get(key).close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
